Welcome back.
In this lecture we're going to finish up our admin system by creating some common commands that many
admin systems have.
So let's just go ahead and get started.
One common command that a lot of admin systems have is setting the speed of a player.
So here let's go ahead and override this example command to be a speed command.
So the key for this command I'm going to set to speed.
And I'll just set the name of this command uh set speed.
The minimum rank we could keep at moderator, and the usage we can keep at set speed speed, and we
can add even another usage like walk speed.
And then for the parameters, we don't need to change anything because we're going to take a player
and then a number.
And then here for the parameters, we're going to have to change this, because the first parameter
that gets passed to our lambda function is going to be the caller, or aka the person executing the
command.
The next parameter should be our player or that table containing all the players.
So we're going to call it players.
And it's going to be a table containing uh players.
So if it's just one player it'll contain one player.
But if it's multiple it contain multiple and so on.
And then the last parameter we have passed is a number to represent the new speed we want to set for
all the players.
So then what we could do here is we could loop through every single player that is inside of our players
table.
And what we could check here is, first of all, we need to verify if this player actually has a character.
If they don't have a character, then we're just going to continue looping because we cannot set the
walk speed of a player that doesn't have a character.
Otherwise we could do player character dot humanoid, dot walk speed is equal to the new speed, and
then once we're done looping, we can return true and say that we've successfully executed the command
and that's it.
So if we go ahead and test out our game, our command should work just fine.
So let's go ahead and hit a semicolon here.
Type in our colon, and we could do set speed and we could do me, and then we could set our speed to
something like 120.
We hit enter.
Executed successfully.
And now if we walk around, boom!
We are super fast now and then again we can do set speed me and then do a number like 16.
And now our walk speed is back to normal.
Now let's go ahead and test out our message label.
So let's say we do set speed and we try to pass the name of a player that doesn't exist.
Like what if we do um others 100.
There's going to be no others in the game.
So it should tell us that no players exist.
And unfortunately it looks like we got an error.
So let's go ahead and see what our error is.
Attempt to call a table value.
Oh, I see, um, we couldn't display the message because we forgot to call our new function.
Oops.
We forgot to call the constructor, but that's fine.
We just fixed that.
So let's go ahead and apply those script changes and let's try that out again.
So if we do set speed others and do something like 100 there we go.
We get a notice.
No players exist.
So if we try to do set speed and then we pass a name like Jeff 100.
Again no players exist.
If we try to use the command and we don't pass the correct number of parameters.
So what if we just do me and then we don't supply a number, then we're going to get missing arguments
to command.
Oh no.
If we do set speed me and then we don't pass a number but instead we pass something like that, then
we're going to get an error command set speed expected number for argument number two.
But we got nil instead.
Anyways, another cool command we could do is killing other players.
So we can call this command kill.
And we can just basically copy all of this here.
And then just kind of override all of this.
So we can call this command kill.
We can keep it at moderator.
The usage for this would be like kill.
I think that's the only usage you'd want for this command.
And then of course, we only need a player for this command so we can get rid of our new speed parameter.
And when we want to do is we want to loop through every single player.
And if they have a character, we can do player dot, character humanoid and set the health of the humanoid
to zero.
So it should be able to kill all the players passed to our callback function.
Let's go ahead and do some other popular commands like kicking players so we can call this command kick,
where again, we're going to copy all this.
And for this one we can keep it at moderator as well.
We're going to call this command kick.
And the usage for this one could be like kick or boot.
We want to boot a player out.
We could do that as well.
And this is also going to require a string or aka the message we want to give to the player when we
kick them.
And then what we want to do here is we want to loop through every single player, pass this function,
and before we kick them, we got to make sure that they're not an admin as well.
So we're going to get the rank of this player using our comms bind able.
And we're going to invoke to get the rank of this particular player.
So if you remember in our admin handler, if we go down to our on invoke function, we get the rank
of a player.
And then we can go and check to see if this rank is greater than zero or admin enum dot non-admin.
Then we're going to return false and tell them that you cannot kick an admin.
You can't do that.
No kicking admins allow.
Otherwise, if they aren't an admin, then we can just go ahead and kick them and give them the reason
for why they were kicked.
So in here we need to pass a message which is going to be our string, and we can give them the reason
for why they were kicked.
Another popular command is to ban somebody.
So let me copy this and we can call this one ban.
So give it a name of band and we can up the minimum rank to be administrator.
And the usage for this one can just be banned.
And for this one we can also require a player and a string.
And in here we want to make sure we do the same thing.
We want to make sure that this person is not an admin.
If they are an admin then we can say cannot ban an admin.
Otherwise we can create a message and we're going to set it equal to you have been server banned and
we can give them the reason.
And we're going to concatenate our reason string.
And then what we could do is that inside of our admin setting, we're going to access server bands,
and we're going to create a new key value pair in here using the player's user ID.
And we're going to give them this band message.
And then we're going to go ahead and kick this person and give them that message.
So now that because we've inserted this person into our server band's table, any time they try to join
back into the server, they're going to get kicked immediately and given this same server band message.
Now, what if we wanted to go ahead and set the moderator or administrator of a player?
What if we want to give them temporary moderator or permanent moderator or admin and stuff like that?
Well, we can go ahead and create some commands for that.
So for one we can create somebody as a temporary moderator.
We can just call this command mod.
The usage could be something like set mod, we could do temp mod.
Actually I think that would be a good first usage.
So temp mod we could do set mod or we could do server mod or something like that.
And all we need is a player to be passed to the function.
And then what we could do here is we could loop through every single player pass to our callback, and
then we could use our coms bindable again and invoke to.
Set temporary privileges.
For this particular player.
So pass a table with the player and then we could also pass what, um, rank we want to give to this
player.
In that case that's going to be admin enum dot moderator.
So let's go ahead and fill out this set temp privileges action.
So if we go back to our admin handler inside of set temp privileges, what we could do is we could get
the key for this player.
So remember args one is going to be player.
And then args two is going to be the rank.
So is the rank.
So key is equal to two string args one dot user id.
And then the first thing we want to check is we want to check if this person exists within the admin
settings.py ranks.
So if they're already hard coded into our game, then we're going to return false and tell them that
you cannot set temporary cannot set temporary privileges for a hard coded user.
Otherwise, what we could do is we could check to see if they are within our data store.
So we're going to use the Pcall function.
And we're going to access our admin data store.
And there's a function in there called get async which is to get a value in our data store.
Again remember we have to pass the admin data store itself.
And then we're going to pass the key.
And then from here we can store the results or the success and result from this P call.
And our get async function.
If we were not successful in grabbing any data from this user, then we're going to return false and
say um, a problem occurred with grabbing information from the data store, and we can give them the
problem by formatting with the result from our Pcall function.
Otherwise, if we, uh, were successful and there is a result or a value, then we need to return false
and tell them temporary privileges.
Cannot override permanent privileges for user.
So if we try to give somebody temporary privileges and they already have permanent privileges, then
we don't want to do anything at all.
We're just going to tell them false and hey, we can't do that.
Otherwise, if we make it through all that and we're all good to go, then we can do admin settings,
dot temporary mods, create a new key value pair in there, and our new temporary mod is going to be
of the rank that was passed to our on invoke function.
So for this particular player it's going to be a moderator.
And then we can call our setup admin for function and pass our player which is args one.
And then we can return true.
And then for setting permanent privileges it's going to be pretty similar.
Um, the first thing we want to make sure of is that we're not running in studio.
So if run service is studio, oops is studio, then we're going to return false and tell them we cannot
set data store in studio.
Otherwise.
Again we're going to get the key for this player.
So again.
ARGs, one is a player and then args two is the rank.
We're going to check inside of admin settings dot player ranks to make sure they are not a hardcoded
user.
If they are, then we're going to return false and say cannot set permanent privileges.
For a hard coded user.
Otherwise, what we could do is we could do admin settings.
Uh, we can just set them inside of the temporary mods table.
That way it's faster for our git rank function to find this player.
And then we're also going to store them within the data store.
So we call.
Admin data store.
And we're going to use the set async function again.
Pass the data store itself and then the key for the data store.
And then the value we want to store at that key which is going to be argument number two.
If we were successful in setting up the data store, then we want to set up admin for this player.
And then we can go ahead.
Return.
Success and result at the end here and again, I'm storing this player inside of our temporary mods
uh, table.
That way it's easier for when we call our git rank, uh, function.
It can just go ahead and look inside of this table without having to, uh, use any async functions
to grab information from the data stored.
Otherwise.
Last one we could fill out here is for removing privileges off of a player.
So again we could do if run service is studio.
Then we're going to return false because again, we don't want to mess with data stores in studio,
so cannot set data store in studio.
Otherwise we're going to get the key for this player.
So two string args one dot user id.
So this is going to be the same thing across the board here args one.
Is a player and args two.
Actually, we don't even need argument number two.
It's just going to be the player.
Anyways, we get there, uh, ki and then, uh, the first thing we want to check is if there are a
hardcoded user.
So if player ranks and we find them, then we're going to return false and tell them cannot revoke perms
of a hardcoded user because there's no point.
Otherwise if they have a key value pair within our admin settings dot temporary mods, then we can just
set that to nil.
And then we're going to access our data store again.
So success result is equal to p call.
And actually I'm going to pass a lambda function here instead.
Because what we want to do is we want to see if there's a result within admin data store, get async
and pass this key.
If there is a result then we want to do admin data store uh remove async and pass the key.
So we're removing this player from our data store.
If we're successful in doing that then we can go ahead and remove admin from this player.
And then at the very end, we can go ahead and return success and the results.
All right.
Very cool.
So let's go ahead and go back to our commands module script.
And then we can store the success and result from our bindable.
And if we were not successful in setting this player as a temporary moderator, then we're just going
to return false and say, encountered a problem setting temporary privileges for player, and we're
going to put a directive here.
And we can tell them that the error was this.
And we're going to put again another directive.
And then we can go ahead and format this string and pass the player name.
And then the result from our bindable.
If we were successful in setting them as a temporary moderator, then what I want to do is I want to
use the task delay function, and I want to delay a function from running for five seconds.
Because what's going on here is that if we were successful in setting temporary privileges for a player,
that means the guy, if they had one, got destroyed and then a new one was added back to him.
So I'm delaying this function by five seconds just to give that player enough time to replicate that
guy on their end and run all the code in the GUI before we fire to the client to display them a message
on their screen, because we're going to use the comms event and fire to this client.
That we want them to display a message, and the message is going to be something like this.
We could tell them that oops.
We could tell them that, uh, you have been granted server moderator.
And then we can kind of do a similar process here for giving somebody a permanent moderator.
So we could do permanent mod.
Uh, we'll call this permanent mod.
And the usage for this one could be like uh, just parm mod.
We only need a player here.
And again we're going to invoke our comms bind able to instead set permanent privileges for this player.
And then again if that wasn't successful we're going to tell them that we encountered a problem setting
permanent privileges for this player.
Otherwise if we were successful again we're going to wait five seconds and then tell the player that
they've been granted.
Permanent moderator.
And guess what?
We could do the exact same thing for giving a player temporary admin so we can go ahead and create a
new key value pair.
We're going to call this command admin.
The name is going to be just admin and the usage can be temp admin set admin server admin.
We could do a bunch of different usages here.
And we're going to basically, again, do the exact same thing here, set temporary privileges.
And that's going to be of the privileges dot admin.
Otherwise if it's not successful again we give them an error message.
Otherwise if we were successful we're going to tell them you have been granted server admin.
And one last time let's go ahead and copy this function here.
And let's do it for giving somebody permanent admin.
So Perme admin we'll do permanent admin.
And we can actually change the minimum rank for this too.
So we could set this to be an owner only command.
So owner only.
So if we want to give somebody permanent admin again set firm privileges.
We'll set this to admin.
Again encountered a problem and then you have been granted permanent admin.
Last but not least, we can create a command for getting rid of admin of a player.
So we call this remove admin.
We can give the name something like remove privileges.
This will be an own or only command.
The usage will be something like we could do revoke perms or we could do remove perms, whatever.
And then what I want to do inside of this for loop is I want to use our comms bindable, and I want
to invoke the action of removing privileges for this particular player here.
And again we can create two variables success and result.
If we were not successful and removing the privileges for this player, we're going to return false
and give a message like encountered a problem removing privileges for player.
Put a directive in here and then give an error message.
So we'll need another directive.
Format this function to replace those directives with the player name, and then the result from our
invoke function.
All right.
And then that's all we need to do for that one.
So now that we've got these neat little functions set up, let's go ahead and test them out.
So let me open up my command line here.
If I type in my colon, there we go.
Shows all of the commands that I have access to use, such as permanent modding, a player, killing
a player, revoking permissions, banning a player temporary, all that fun stuff.
So let's go ahead and try to ban myself, which shouldn't work.
So if I do ban me and I give a message like you suck, we're going to get a problem.
The command ban encountered a problem during execution.
Cannot ban an admin.
Hey, you can't ban us because I'm the owner of the game again, this is the same problem if we were
trying to kick an admin.
So if I do kick me hahaha again, cannot kick an admin.
All right, what if I try to set permanent privileges for myself?
So if I do like temp oops temp admin me we can't do that.
The command admin encountered a problem during execution.
The problem is we encountered a problem setting temporary privileges for us because we cannot set temporary
privileges for a hardcoded user.
Cool.
What if we try to give permanent moderator to myself?
Again cannot set data store in studio.
If I try to do permanent, uh, admin.
Oops, looks like I forgot to change the name.
So permanent admin me.
The command doesn't exist.
Think I forgot to change a name in here?
Let me go back.
Palm admin admin.
Oh, let me change that usage there.
So palm admin.
Okay.
It looks good.
So let's go ahead and test that out.
So we could do palm admin.
Me again.
We're going to get an error that we cannot set data stores in studio.
And of course I can also use these commands from chat.
So if I try to do something like set speed me 100, we're going to have no problem doing that whatsoever.
But if I screw up and do set speed me something like, actually, let me change this to a string.
We're going to get a problem there because we didn't enter in the correct argument for that parameter.
And again, I could do something like, well, let's say I type in a command that doesn't exist.
So like, uh, something blah, blah blah, we're going to get command does not exist, but I can go
ahead and kill myself using the kill me.
Alrighty, so congratulations on finishing this project.
We are done!
Hopefully you've gained a solid understanding of how an admin system works and how you can create your
own admin systems and commands.
The completed model is attached to this lecture along with some additional functions I've added inside
of our admin system.
I'll see you in the next lecture.